#include "Precompile.h"
#include "InputSystem.h"
#include "GUIManager.h"

namespace Input{
	InputSystem::InputSystem():m_synced(false){
		m_keyMapFront[EIK_ESCAPE] = KeyData();
		m_keyMapFront[EIK_1] = KeyData();
		m_keyMapFront[EIK_2] = KeyData();
		m_keyMapFront[EIK_3] = KeyData();
		m_keyMapFront[EIK_4] = KeyData();
		m_keyMapFront[EIK_5] = KeyData();
		m_keyMapFront[EIK_6] = KeyData();
		m_keyMapFront[EIK_7] = KeyData();
		m_keyMapFront[EIK_8] = KeyData();
		m_keyMapFront[EIK_9] = KeyData();
		m_keyMapFront[EIK_0] = KeyData();
		m_keyMapFront[EIK_MINUS] = KeyData();
		m_keyMapFront[EIK_EQUALS] = KeyData();
		m_keyMapFront[EIK_BACK] = KeyData();
		m_keyMapFront[EIK_TAB] = KeyData();
		m_keyMapFront[EIK_Q] = KeyData();
		m_keyMapFront[EIK_W] = KeyData();
		m_keyMapFront[EIK_E] = KeyData();
		m_keyMapFront[EIK_R] = KeyData();
		m_keyMapFront[EIK_T] = KeyData();
		m_keyMapFront[EIK_Y] = KeyData();
		m_keyMapFront[EIK_U] = KeyData();
		m_keyMapFront[EIK_I] = KeyData();
		m_keyMapFront[EIK_O] = KeyData();
		m_keyMapFront[EIK_P] = KeyData();
		m_keyMapFront[EIK_LBRACKET] = KeyData();
		m_keyMapFront[EIK_RBRACKET] = KeyData();
		m_keyMapFront[EIK_RETURN] = KeyData();
		m_keyMapFront[EIK_LCONTROL] = KeyData();
		m_keyMapFront[EIK_A] = KeyData();
		m_keyMapFront[EIK_S] = KeyData();
		m_keyMapFront[EIK_D] = KeyData();
		m_keyMapFront[EIK_F] = KeyData();
		m_keyMapFront[EIK_G] = KeyData();
		m_keyMapFront[EIK_H] = KeyData();
		m_keyMapFront[EIK_J] = KeyData();
		m_keyMapFront[EIK_K] = KeyData();
		m_keyMapFront[EIK_L] = KeyData();
		m_keyMapFront[EIK_SEMICOLON] = KeyData();
		m_keyMapFront[EIK_APOSTROPHE] = KeyData();
		m_keyMapFront[EIK_GRAVE] = KeyData();
		m_keyMapFront[EIK_LSHIFT] = KeyData();
		m_keyMapFront[EIK_BACKSLASH] = KeyData();
		m_keyMapFront[EIK_Z] = KeyData();
		m_keyMapFront[EIK_X] = KeyData();
		m_keyMapFront[EIK_C] = KeyData();
		m_keyMapFront[EIK_V] = KeyData();
		m_keyMapFront[EIK_B] = KeyData();
		m_keyMapFront[EIK_N] = KeyData();
		m_keyMapFront[EIK_M] = KeyData();
		m_keyMapFront[EIK_COMMA] = KeyData();
		m_keyMapFront[EIK_PERIOD] = KeyData();
		m_keyMapFront[EIK_SLASH] = KeyData();
		m_keyMapFront[EIK_RSHIFT] = KeyData();
		m_keyMapFront[EIK_MULTIPLY] = KeyData();
		m_keyMapFront[EIK_LMENU] = KeyData();
		m_keyMapFront[EIK_SPACE] = KeyData();
		m_keyMapFront[EIK_CAPITAL] = KeyData();
		m_keyMapFront[EIK_F1] = KeyData();
		m_keyMapFront[EIK_F2] = KeyData();
		m_keyMapFront[EIK_F3] = KeyData();
		m_keyMapFront[EIK_F4] = KeyData();
		m_keyMapFront[EIK_F5] = KeyData();
		m_keyMapFront[EIK_F6] = KeyData();
		m_keyMapFront[EIK_F7] = KeyData();
		m_keyMapFront[EIK_F8] = KeyData();
		m_keyMapFront[EIK_F9] = KeyData();
		m_keyMapFront[EIK_F10] = KeyData();
		m_keyMapFront[EIK_NUMLOCK] = KeyData();
		m_keyMapFront[EIK_SCROLL] = KeyData();
		m_keyMapFront[EIK_NUMPAD7] = KeyData();
		m_keyMapFront[EIK_NUMPAD8] = KeyData();
		m_keyMapFront[EIK_NUMPAD9] = KeyData();
		m_keyMapFront[EIK_SUBTRACT] = KeyData();
		m_keyMapFront[EIK_NUMPAD4] = KeyData();
		m_keyMapFront[EIK_NUMPAD5] = KeyData();
		m_keyMapFront[EIK_NUMPAD6] = KeyData();
		m_keyMapFront[EIK_ADD] = KeyData();
		m_keyMapFront[EIK_NUMPAD1] = KeyData();
		m_keyMapFront[EIK_NUMPAD2] = KeyData();
		m_keyMapFront[EIK_NUMPAD3] = KeyData();
		m_keyMapFront[EIK_NUMPAD0] = KeyData();
		m_keyMapFront[EIK_DECIMAL] = KeyData();
		m_keyMapFront[EIK_OEM_102] = KeyData();
		m_keyMapFront[EIK_F11] = KeyData();
		m_keyMapFront[EIK_F12] = KeyData();
		m_keyMapFront[EIK_F13] = KeyData();
		m_keyMapFront[EIK_F14] = KeyData();
		m_keyMapFront[EIK_F15] = KeyData();
		m_keyMapFront[EIK_KANA] = KeyData();
		m_keyMapFront[EIK_ABNT_C1] = KeyData();
		m_keyMapFront[EIK_CONVERT] = KeyData();
		m_keyMapFront[EIK_NOCONVERT] = KeyData();
		m_keyMapFront[EIK_YEN] = KeyData();
		m_keyMapFront[EIK_ABNT_C2] = KeyData();
		m_keyMapFront[EIK_NUMPADEQUALS] = KeyData();
		m_keyMapFront[EIK_PREVTRACK] = KeyData();
		m_keyMapFront[EIK_AT] = KeyData();
		m_keyMapFront[EIK_COLON] = KeyData();
		m_keyMapFront[EIK_UNDERLINE] = KeyData();
		m_keyMapFront[EIK_KANJI] = KeyData();
		m_keyMapFront[EIK_STOP] = KeyData();
		m_keyMapFront[EIK_AX] = KeyData();
		m_keyMapFront[EIK_UNLABELED] = KeyData();
		m_keyMapFront[EIK_NEXTTRACK] = KeyData();
		m_keyMapFront[EIK_NUMPADENTER] = KeyData();
		m_keyMapFront[EIK_RCONTROL] = KeyData();
		m_keyMapFront[EIK_MUTE] = KeyData();
		m_keyMapFront[EIK_CALCULATOR] = KeyData();
		m_keyMapFront[EIK_PLAYPAUSE] = KeyData();
		m_keyMapFront[EIK_MEDIASTOP] = KeyData();
		m_keyMapFront[EIK_VOLUMEDOWN] = KeyData();
		m_keyMapFront[EIK_VOLUMEUP] = KeyData();
		m_keyMapFront[EIK_WEBHOME] = KeyData();
		m_keyMapFront[EIK_NUMPADCOMMA] = KeyData();
		m_keyMapFront[EIK_DIVIDE] = KeyData();
		m_keyMapFront[EIK_SYSRQ] = KeyData();
		m_keyMapFront[EIK_RMENU] = KeyData();
		m_keyMapFront[EIK_PAUSE] = KeyData();
		m_keyMapFront[EIK_HOME] = KeyData();
		m_keyMapFront[EIK_UP] = KeyData();
		m_keyMapFront[EIK_PRIOR] = KeyData();
		m_keyMapFront[EIK_LEFT] = KeyData();
		m_keyMapFront[EIK_RIGHT] = KeyData();
		m_keyMapFront[EIK_END] = KeyData();
		m_keyMapFront[EIK_DOWN] = KeyData();
		m_keyMapFront[EIK_NEXT] = KeyData();
		m_keyMapFront[EIK_INSERT] = KeyData();
		m_keyMapFront[EIK_DELETE] = KeyData();
		m_keyMapFront[EIK_LWIN] = KeyData();
		m_keyMapFront[EIK_RWIN] = KeyData();
		m_keyMapFront[EIK_APPS] = KeyData();
		m_keyMapFront[EIK_POWER] = KeyData();
		m_keyMapFront[EIK_SLEEP] = KeyData();
		m_keyMapFront[EIK_WAKE] = KeyData();
		m_keyMapFront[EIK_WEBSEARCH] = KeyData();
		m_keyMapFront[EIK_WEBFAVORITES] = KeyData();
		m_keyMapFront[EIK_WEBREFRESH] = KeyData();
		m_keyMapFront[EIK_WEBSTOP] = KeyData();
		m_keyMapFront[EIK_WEBFORWARD] = KeyData();
		m_keyMapFront[EIK_WEBBACK] = KeyData();
		m_keyMapFront[EIK_MYCOMPUTER] = KeyData();
		m_keyMapFront[EIK_MAIL] = KeyData();
		m_keyMapFront[EIK_MEDIASELECT] = KeyData();

		m_keyMapFront[EIMOUSEBUTTON_0] = KeyData();
		m_keyMapFront[EIMOUSEBUTTON_1] = KeyData();
		m_keyMapFront[EIMOUSEBUTTON_2] = KeyData();
		m_keyMapFront[EIMOUSEBUTTON_3] = KeyData();
		m_keyMapFront[EIMOUSEBUTTON_4] = KeyData();
		m_keyMapFront[EIMOUSEBUTTON_5] = KeyData();
		m_keyMapFront[EIMOUSEBUTTON_6] = KeyData();
		m_keyMapFront[EIMOUSEBUTTON_7] = KeyData();

		m_keyMapBack = m_keyMapFront;

		m_keyMapBackPtr = &m_keyMapBack;
		m_keyMapFrontPtr = &m_keyMapFront;

		m_mouseDataFrontPtr = &m_mouseDataFront;
		m_mouseDataBackPtr = &m_mouseDataBack;

		m_bufferSwapMutex = ThreadLib::ThreadFactory::spawnMutex();
		m_guiMgrMutex = ThreadLib::ThreadFactory::spawnMutex();

		m_mouseSensitivity = 1.0f;
	}

	void InputSystem::synchronizeInput(){
		m_bufferSwapMutex->lock();
		*m_keyMapFrontPtr = *m_keyMapBackPtr;
		*m_mouseDataFrontPtr = *m_mouseDataBackPtr;

		// Inject into gui managers
		m_guiMgrMutex->lock();
		std::set<boost::shared_ptr<Graphics::GUIManager>>::iterator gui_itr = m_GUIManagers.begin();
		while(gui_itr != m_GUIManagers.end()){
			(*gui_itr)->injectMouseInput(float(m_mouseDataBackPtr->deltaX)*m_mouseSensitivity,float(m_mouseDataBackPtr->deltaY)*m_mouseSensitivity);
			gui_itr++;
		}
		m_guiMgrMutex->unlock();

		m_mouseDataBackPtr->deltaX = 0;
		m_mouseDataBackPtr->deltaY = 0;
		m_synced = true;
		m_bufferSwapMutex->unlock();

		update();
	}

	void InputSystem::registerGUIManager(boost::shared_ptr<Graphics::GUIManager> mgr){
		m_guiMgrMutex->lock();
		m_GUIManagers.insert(mgr);
		m_guiMgrMutex->unlock();
	}
	
	void InputSystem::unregisterGUIManager(boost::shared_ptr<Graphics::GUIManager> mgr){
		m_guiMgrMutex->lock();
		m_GUIManagers.erase(mgr);
		m_guiMgrMutex->unlock();
	}

	bool InputSystem::keyPressed_luaWrap(int keyId){
		return keyIsPressed(KeyDefinition(keyId));
	}

	bool InputSystem::keyIsPressed(KeyDefinition key){
		bool status;
		m_bufferSwapMutex->lock();
		status = (*m_keyMapFrontPtr)[key].isPressed;
		m_bufferSwapMutex->unlock();
		return status;
	}

	bool InputSystem::keyWasPressed(KeyDefinition key){
		bool status;
		m_bufferSwapMutex->lock();
		status = (*m_keyMapFrontPtr)[key].wasPressed;
		m_bufferSwapMutex->unlock();
		return status;
	}

	std::pair<float,float> InputSystem::getMouseDeltaMovement(){
		std::pair<float,float> delta;
		m_bufferSwapMutex->lock();
		delta.first = float(m_mouseDataFrontPtr->deltaX)*m_mouseSensitivity;
		delta.second = float(m_mouseDataFrontPtr->deltaY)*m_mouseSensitivity;
		m_bufferSwapMutex->unlock();
		return delta;
	}
	
	std::pair<unsigned int,unsigned int> InputSystem::getMousePosition(){
		std::pair<unsigned int, unsigned int> choords;
		m_bufferSwapMutex->lock();
		choords.first = m_mouseDataFrontPtr->xPos;
		choords.second = m_mouseDataFrontPtr->yPos;
		m_bufferSwapMutex->unlock();
		return choords;
	}

	int InputSystem::getMouseWheelMovement(){
		int wheel;
		m_bufferSwapMutex->lock();
		wheel = m_mouseDataFrontPtr->zPos;
		m_bufferSwapMutex->unlock();
		return wheel;
	}
}